package com.lin.pay.paypal.v2;

import com.google.gson.Gson;
import com.lin.common.constant.CustomerRedisConstant;
import com.lin.common.utils.HttpClientUtils;
import com.lin.pay.paypal.v1.PaypalUtils;
import com.lin.pay.paypal.v1.vo.TokenResult;
import com.lin.pay.paypal.v2.dto.orders.CreateOrderDto;
import com.lin.pay.paypal.v2.dto.orders.Refund;
import com.lin.properties.PayProperties;
import com.paypal.payments.Capture;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.message.BasicHeader;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class OrderService {
    private static final Logger log = LoggerFactory.getLogger(OrderService.class);
    private Gson g = new Gson();
    @Autowired
    private PayProperties payProperties;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * https://developer.paypal.com/docs/api/payments/v2/#captures_refund
     *
     * @param captureId
     * @return
     * @throws UnsupportedEncodingException
     */
    public Refund captureRefund(String captureId, String amt, String currency) throws UnsupportedEncodingException {
        Header[] headers = new Header[]{
                new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json"),
                new BasicHeader(HttpHeaders.AUTHORIZATION, "Bearer " + getToken()),
        };
        String result = HttpClientUtils.httpPost(payProperties.getPaypal().get(PayProperties.CAPTURE_REFUND).replace("{capture_id}", captureId), Helper.buildRefundReq(amt, currency), headers);
        return g.fromJson(result, Refund.class);
    }

    /**
     * https://developer.paypal.com/docs/api/orders/v2/#orders_capture
     *
     * @param orderId
     * @return
     * @throws UnsupportedEncodingException
     */
    public Capture capturePayment(String orderId) throws UnsupportedEncodingException {
        Header[] headers = new Header[]{
                new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json"),
                new BasicHeader(HttpHeaders.AUTHORIZATION, "Bearer " + getToken()),
        };
        String result = HttpClientUtils.httpPost(payProperties.getPaypal().get(PayProperties.CAPTURE_PAYMENT).replace("{id}", orderId), null, headers);
        return g.fromJson(result, Capture.class);
    }

    public CreateOrderDto orderDetail(String orderId) throws UnsupportedEncodingException {
        Header[] headers = new Header[]{
                new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json"),
                new BasicHeader(HttpHeaders.AUTHORIZATION, "Bearer " + getToken()),
        };
        String result = HttpClientUtils.httpGet(payProperties.getPaypal().get(PayProperties.ORDER_DETAIL).replace("{id}", orderId), headers);
        return g.fromJson(result, CreateOrderDto.class);
    }

    public CreateOrderDto createOrder(String amt, String currency) throws IOException {
        String result = HttpClientUtils.httpPost(payProperties.getPaypal().get(PayProperties.CREATE_ORDER), Helper.buildCreateOrderRequestBody(amt, currency), Helper.buildHeader(getToken()));
        return g.fromJson(result, CreateOrderDto.class);
    }


    private String getToken() throws UnsupportedEncodingException {
        RBucket<String> rb = redissonClient.getBucket(CustomerRedisConstant.PAYPAL_ACCESS_TOKEN);
        if (rb.get() == null) {
            Header[] headers = new Header[]{
                    new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded"),
                    new BasicHeader(HttpHeaders.AUTHORIZATION, PaypalUtils.getBasicBearerToken(payProperties.getPaypal().get(PayProperties.CLIENT_ID), payProperties.getPaypal().get(PayProperties.CLIENT_SECRET))),
                    new BasicHeader("PayPal-Partner-Attribution-Id", PayProperties.BN_CODE)
            };
            Map<String, String> map = new HashMap<>();
            map.put("grant_type", "client_credentials");
            String s = HttpClientUtils.post(payProperties.getPaypal().get(PayProperties.ACCESS_TOKEN_URL), map, headers);
            log.info("access_token is: {}", s);
            Gson g = new Gson();
            TokenResult tr = g.fromJson(s, TokenResult.class);
            rb.set(tr.getAccess_token(), CustomerRedisConstant.PAYPAL_ACCESS_TOKEN_TIMEOUT, TimeUnit.SECONDS);
            return tr.getAccess_token();
        } else {
            log.info("access_token get by redis");
            return rb.get();
        }
    }

    public void setPayProperties(PayProperties payProperties) {
        this.payProperties = payProperties;
    }

    public void setRedissonClient(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }
}
